#include <commands/client/c_send_login.h>
#include <app/states/connectionState.h>
#include <app/states/modelInfoState.h>
#include <app/states/cacheState.h>

#include <Poco/Path.h>
#include <Poco/File.h>

#include <sstream>
#include <fstream>

using std::stringstream;
using std::endl;

REGISTER_COMMAND(CLIENT_SEND_LOGIN, c_send_login)

c_send_login::c_send_login() : command(0, NULL) {
  model_name = "";
  user_name = "";
  password = "";
}

c_send_login::c_send_login(unsigned int _type_id, streamingConnection *_connection) : command(_type_id, _connection) {
  model_name = "";
  user_name = "";
  password = "";
}

void 
c_send_login::setData(const char *model_name, const char *user_name, const char *password) {
  this->model_name = model_name;
  this->user_name = user_name;
  this->password = password;
}

void
c_send_login::decode(stringstream &bytes_stream, int size) {
#ifdef SERVER
  
  #ifdef DEBUG_INFO
  std::cerr << "SERVER DECODE: c_send_login" << std::endl;
  #endif

  bytes_stream >> model_name;
  bytes_stream >> user_name;
  bytes_stream >> password;

  streamingConnection *conn = getconnection();
  cacheState *chstate = GET_STATE(cacheState, conn);

  // read login file
  Poco::Path login_path;
  login_path.pushDirectory(chstate->getCacheDir().toString());
  login_path.pushDirectory(model_name);
  login_path.pushDirectory("user_profiles");
  login_path.pushDirectory(user_name);
  Poco::File loginfile(Poco::Path(login_path.toString(), user_name + ".def"));

  string fullname = loginfile.path();
  std::fstream input(fullname.c_str(), std::ios::in | std::ios::binary);
  if (input.is_open()) {
    std::string pass;
    input >> pass;

    if (password == pass) {
      
      // create modelInfoState
      Poco::Path model_path;
      model_path.pushDirectory(chstate->getCacheDir().toString());
      model_path.pushDirectory(model_name);
      Poco::File modelInfofile(Poco::Path(model_path.toString(), model_name + ".def"));

      modelInfoState *mfstate = GET_STATE(modelInfoState, conn);
      mfstate->loadInfo(modelInfofile);

      // create new connection state with predefined values
      connectionState *cstate = GET_STATE(connectionState, conn);
      cstate->setModelName(model_name);
      cstate->setUserName(user_name);
      cstate->setPassword(password);
      cstate->setLoginAccepted(true);
      
      command *cmd = (command *) commandFactory::instance().createCommand(SERVER_ACCEPT_CONNECTION, conn);
      cmd->execute();
      delete cmd;

      input.close();
      return;
    }
  }

  input.close();

  connectionState *cstate = GET_STATE(connectionState, conn);
  cstate->setModelName(model_name);
  cstate->setUserName(user_name);
  cstate->setPassword(password);
  cstate->setLoginAccepted(false);

  conn->getSession().requestFinish();

  command *cmd = (command *) commandFactory::instance().createCommand(SERVER_REJECT_CONNECTION, conn);
  cmd->execute();
  delete cmd;

#endif
}

void 
c_send_login::execute() {
#ifdef CLIENT
  
  #ifdef DEBUG_INFO
  std::cerr << "CLIENT EXECUTE: c_send_login" << std::endl;
  #endif

  unsigned int *id = new unsigned int[1];
  unsigned int *total_size = new unsigned int[1];
  unsigned int data_size;

  total_size[0] = sizeof(unsigned int); // total size itself

  id[0] = getTypeId();
  total_size[0] += sizeof(unsigned int); // id size

  stringstream bytes(ios::out | ios::in | ios::binary);
   bytes << model_name << endl;
   bytes << user_name << endl;
   bytes << password << endl;
   bytes.seekg(0, ios::end);
  data_size = bytes.tellg();

  unsigned char *data = new unsigned char[data_size];
  bytes.seekg(0, ios::beg);
  bytes.read((char *)data, data_size);

  total_size[0] += data_size;
  
  sendBytes(total_size, sizeof(unsigned int));
  sendBytes(id, sizeof(unsigned int));

  sendBytes(data, data_size);
  
#endif
}
